#include <iostream>
#include <vector>
#include <string>
#include <unordered_map>
#include <chrono>
#include <thread>
#include <sw/redis++/redis++.h>

using namespace std;
using namespace sw::redis;

// set and get
void Test1(Redis& redis)
{
    redis.flushall();
    cout << "get and set" << endl;

    // 设置 key
    redis.set("key", "1");
    auto val1 = redis.get("key");
    cout << "val1: " << val1.value() << endl;

    // 修改 key
    redis.set("key", "2");
    val1 = redis.get("key");
    cout << "val1: " << val1.value() << endl;
}

// set with expire
void Test2(Redis& redis)
{
    redis.flushall();
    cout << "set with expire" << endl;

    redis.set("key", "111", 10s);
    this_thread::sleep_for(3s);

    auto time = redis.ttl("key");
    cout << "time: " << time << endl;
}

// set NX and XX
void Test3(Redis& redis)
{
    redis.flushall();
    cout << "set NX and XX" << endl;

    // NOT_EXIST: 不存在才进行设置
    redis.set("key1", "111", 0s, UpdateType::NOT_EXIST);
    auto val1 = redis.get("key1");
    if(val1)
        cout << "val1: " << val1.value() << endl;
    else
        cout << "val1 not exists" << endl;
    
    // EXIST: 存在才进行设置
    redis.set("key2", "222", 0s, UpdateType::EXIST);
    auto val2 = redis.get("key2");
    if(val2)
        cout << "val2: " << val2.value() << endl;
    else
        cout << "val2 not exists" << endl;
}

// mset and mget
void Test4(Redis& redis)
{
    redis.flushall();
    cout << "mset and mget" << endl;

    // 第一种写法：使用初始化列表描述多个键值对
    // redis.mset({make_pair("key1", "111"), make_pair("key2", "222"), make_pair("key3", "333")});
    
    // 第二种写法：将多个键值对提前存在容器中，以迭代器的形式来进行初始化
    vector<pair<string, string>> keys = {
        {"key1", "111"},
        {"key2", "222"},
        {"key3", "333"}
    };
    redis.mset(keys.begin(), keys.end());
    
    vector<OptionalString> vals;
    auto it = back_inserter(vals);
    redis.mget({"key1", "key2", "key3", "key4"}, it);
    
    for(auto& e : vals)
    {
        if(e)
            cout << e.value() << endl;
        else
            cout << "key not exists" << endl; 
    }
}

// setrange and getrange
void Test5(Redis& redis)
{
    redis.flushall();
    cout << "setrange and getrange" << endl;

    redis.set("key", "hello world");

    string ret = redis.getrange("key", 6, -1);
    cout << "ret: " << ret << endl;

    redis.setrange("key", 0, "welcome to Canada");
    auto val = redis.get("key");
    cout << "val:" << val.value() << endl;
}

// incr and decr
void Test6(Redis& redis)
{
    redis.flushall();
    cout << "incr and decr" << endl;

    redis.set("key", "728");
    long long ret = redis.incr("key");
    cout << "ret: " << ret << endl;
    ret = redis.incrby("key", 101);
    cout << "ret: " << ret << endl;
    cout << redis.get("key").value() << endl;

    ret = redis.decr("key");
    cout << "ret: " << ret << endl;
    ret = redis.decrby("key", 101);
    cout << "ret: " << ret << endl;
    cout << redis.get("key").value() << endl;

    // cout << typeid(redis.get("key")).name() << endl;
}

int main()
{
    sw::redis::Redis redis("tcp://127.0.0.1:6379");
    // Test1(redis);
    // Test2(redis);
    // Test3(redis);
    // Test4(redis);
    // Test5(redis);
    Test6(redis);

    return 0;
}